package com.jcn.seckill.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

import com.jcn.seckill.domain.MiaoshaUser;
import com.jcn.seckill.redis.GoodsKey;
import com.jcn.seckill.redis.RedisService;
import com.jcn.seckill.result.Result;
import com.jcn.seckill.service.GoodsService;
import com.jcn.seckill.service.MiaoshaUserService;
import com.jcn.seckill.vo.GoodsDetailVo;
import com.jcn.seckill.vo.GoodsVo;

//定义一个 Controller 控制器
@Controller
//映射请求,指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置
@RequestMapping("/goods")
public class GoodsController {

	//对类成员变量、方法及构造函数进行标注，完成自动装配的工作
	//@Autowired标注可以放在成员变量上，也可以放在成员变量的set方法上，也可以放在任意方法上表示
	@Autowired
	//注入服务   
	MiaoshaUserService userService;
	
	//对类成员变量、方法及构造函数进行标注，完成自动装配的工作
	//@Autowired标注可以放在成员变量上，也可以放在成员变量的set方法上，也可以放在任意方法上表示
	@Autowired
	//注入服务   
	RedisService redisService;
	
	//对类成员变量、方法及构造函数进行标注，完成自动装配的工作
	//@Autowired标注可以放在成员变量上，也可以放在成员变量的set方法上，也可以放在任意方法上表示
	@Autowired
	//注入服务   
	GoodsService goodsService;
	
	//对类成员变量、方法及构造函数进行标注，完成自动装配的工作
	//@Autowired标注可以放在成员变量上，也可以放在成员变量的set方法上，也可以放在任意方法上表示
	@Autowired
	//注入服务   
	ThymeleafViewResolver thymeleafViewResolver;
	
	//对类成员变量、方法及构造函数进行标注，完成自动装配的工作
	//@Autowired标注可以放在成员变量上，也可以放在成员变量的set方法上，也可以放在任意方法上表示
	@Autowired
	//注入服务   
	ApplicationContext applicationContext;
	
	/**
	 * QPS:1267 load:15 mysql
	 * 5000 * 10
	 * QPS:2884, load:5 
	 * */
	//映射请求,指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置
	//produces="text/html"：直接返回string型的html源代码
    @RequestMapping(value="/to_list", produces="text/html")
    /**
     * 返回结果直接写入 HTTP response body 中，
     * 一般在异步获取数据时使用【也就是AJAX】，
     * 在使用 @RequestMapping后，返回值通常解析为跳转路径，
     * 但是加上 @ResponseBody 后返回结果不会被解析为跳转路径，
     * 而是直接写入 HTTP response body 中。 比如异步获取 json 数据，
     * 加上 @ResponseBody 后，会直接返回 json 数据。@RequestBody 
     * 将 HTTP 请求正文插入方法中，
     * 使用适合的 HttpMessageConverter 将请求体写入某个对象。
     * */
    @ResponseBody
    public String list(HttpServletRequest request, HttpServletResponse response, Model model,MiaoshaUser user) {
    	model.addAttribute("user", user);
    	//1.取缓存
//    	String html = redisService.get(GoodsKey.getGoodsList, "", String.class);
//    	if(!StringUtils.isEmpty(html)) {//如果不是空则直接返回
//    		return html;
//    	}
    	//查询商品列表
    	List<GoodsVo> goodsList = goodsService.listGoodsVo();
    	//传入页面上
    	model.addAttribute("goodsList", goodsList);
//    	 return "goods_list";
    	//页面数据
    	WebContext ctx = new WebContext(request,response,
    			request.getServletContext(),request.getLocale(), model.asMap());
    	//2.如果取不到缓存则，手动渲染
    	String html = thymeleafViewResolver.getTemplateEngine().process("goods_list", ctx);
    	if(!StringUtils.isEmpty(html)) {//如果模板不是空，则保持到缓存中去，最终返回html页面数据
    		//没有参数，无论任何人访问，都是同一个页面，粒度是最大的。
    		redisService.set(GoodsKey.getGoodsList, "", html);
    	}
    	return html;
    }
    
    //映射请求,指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置
    @RequestMapping(value="/to_detail2/{goodsId}",produces="text/html")
    /**
     * 返回结果直接写入 HTTP response body 中，
     * 一般在异步获取数据时使用【也就是AJAX】，
     * 在使用 @RequestMapping后，返回值通常解析为跳转路径，
     * 但是加上 @ResponseBody 后返回结果不会被解析为跳转路径，
     * 而是直接写入 HTTP response body 中。 比如异步获取 json 数据，
     * 加上 @ResponseBody 后，会直接返回 json 数据。@RequestBody 
     * 将 HTTP 请求正文插入方法中，
     * 使用适合的 HttpMessageConverter 将请求体写入某个对象。
     * */
    @ResponseBody
    //URL缓存
    public String detail2(HttpServletRequest request, HttpServletResponse response, Model model,MiaoshaUser user,
    		@PathVariable("goodsId")long goodsId) {
    	model.addAttribute("user", user);
    	
    	//1.取缓存
    	//URL缓存：拼上goodsId，不同页面有不同的详情，根据参数来区分，粒度小一些
    	String html = redisService.get(GoodsKey.getGoodsDetail, ""+goodsId, String.class);
    	if(!StringUtils.isEmpty(html)) {
    		return html;
    	}
    	//2.手动渲染
    	GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
    	model.addAttribute("goods", goods);
    	
    	long startAt = goods.getStartDate().getTime();
    	long endAt = goods.getEndDate().getTime();
    	long now = System.currentTimeMillis();
    	
    	int miaoshaStatus = 0;
    	int remainSeconds = 0;
    	if(now < startAt ) {//秒杀还没开始，倒计时
    		miaoshaStatus = 0;
    		remainSeconds = (int)((startAt - now )/1000);
    	}else  if(now > endAt){//秒杀已经结束
    		miaoshaStatus = 2;
    		remainSeconds = -1;
    	}else {//秒杀进行中
    		miaoshaStatus = 1;
    		remainSeconds = 0;
    	}
    	model.addAttribute("miaoshaStatus", miaoshaStatus);
    	model.addAttribute("remainSeconds", remainSeconds);
//        return "goods_detail";
    	
    	WebContext ctx = new WebContext(request,response,
    			request.getServletContext(),request.getLocale(), model.asMap());
    	html = thymeleafViewResolver.getTemplateEngine().process("goods_detail", ctx);
    	if(!StringUtils.isEmpty(html)) {
    		//URL缓存：拼上goodsId，不同页面有不同的详情
    		redisService.set(GoodsKey.getGoodsDetail, ""+goodsId, html);
    	}
    	return html;
    }
    
    //商品详情
    //映射请求,指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置
    //服务端只需要写接口即可
    @RequestMapping(value="/detail/{goodsId}")
    /**
     * 返回结果直接写入 HTTP response body 中，
     * 一般在异步获取数据时使用【也就是AJAX】，
     * 在使用 @RequestMapping后，返回值通常解析为跳转路径，
     * 但是加上 @ResponseBody 后返回结果不会被解析为跳转路径，
     * 而是直接写入 HTTP response body 中。 比如异步获取 json 数据，
     * 加上 @ResponseBody 后，会直接返回 json 数据。@RequestBody 
     * 将 HTTP 请求正文插入方法中，
     * 使用适合的 HttpMessageConverter 将请求体写入某个对象。
     * */
    @ResponseBody
    public Result<GoodsDetailVo> detail(HttpServletRequest request, HttpServletResponse response, Model model,MiaoshaUser user,
    		@PathVariable("goodsId")long goodsId) { //id不进行自增，防止被别人遍历，一般用snowflake算法
    	GoodsVo goods = goodsService.getGoodsVoByGoodsId(goodsId);
    	long startAt = goods.getStartDate().getTime();
    	long endAt = goods.getEndDate().getTime();
    	long now = System.currentTimeMillis();
    	int miaoshaStatus = 0;
    	int remainSeconds = 0;
    	if(now < startAt ) {//秒杀还没开始，倒计时
    		miaoshaStatus = 0;
    		remainSeconds = (int)((startAt - now )/1000);
    	}else  if(now > endAt){//秒杀已经结束
    		miaoshaStatus = 2;
    		remainSeconds = -1;
    	}else {//秒杀进行中
    		miaoshaStatus = 1;
    		remainSeconds = 0;
    	}
    	//页面静态化
    	GoodsDetailVo vo = new GoodsDetailVo();
    	vo.setGoods(goods);
    	vo.setUser(user);
    	vo.setRemainSeconds(remainSeconds);
    	vo.setMiaoshaStatus(miaoshaStatus);
    	return Result.success(vo);
    }
    
    
}
